package 集合;

//我们知道，List是一种顺序列表，如果有一个存储学生Student实例的List，要在List中根据name查找某个指定的Student的分数，应该怎么办？
//最简单的方法是遍历List并判断name是否相等，然后返回指定元素：
//
//List<Student> list = ...
//Student target = null;
//for (Student s : list) {
//    if ("Xiao Ming".equals(s.name)) {
//        target = s;
//        break;
//    }
//}
//System.out.println(target.score);
//
//这种需求其实非常常见，即通过一个键去查询对应的值。使用List来实现存在效率非常低的问题，因为平均需要扫描一半的元素才能确定，而Map这种键值（key-value）
//映射表的数据结构，作用就是能高效通过key快速查找value（元素）。
//
//用Map来实现根据name查询某个Student的代码如下：

/*import java.util.HashMap;
import java.util.Map;
public class 使用map {
    public static void main(String[] args) {
        Student s = new Student("Xiao Ming", 20,99);
        Map<String, Student> map = new HashMap<>();
        map.put("Xiao Ming", s); // 将"Xiao Ming"和Student实例映射并关联
        map.put("Bob", new Student("Bob",30,100)); // 将"Xiao Ming"和Student实例映射并关联
        map.put("apple", new Student("apple",40,110)); // 将"Xiao Ming"和Student实例映射并关联
//        Student target = map.get("Xiao Ming"); // 通过key查找并返回映射的Student实例
//        System.out.println(target == s); // true，同一个实例
//        System.out.println(target.score); // 99
//        Student another = map.get("Bob"); // 通过另一个key查找
//        System.out.println(another.score); // 未找到返回null

        //通过keySet()遍历：
        for (String key:map.keySet()) {
        	Student value=(Student) map.get(key);
        	System.out.println("1.keySet: key="+key+": "+value.name+": "+value.score+" "+value.age);
        }

        //通过entrySet()遍历：
        for (Map.Entry<String, Student> student:map.entrySet()) {
        	String key=student.getKey();
        	Student value=student.getValue();
        	System.out.println("2.entrySet: key="+key+": "+value.name+": "+value.score+" "+value.age);
        }
        
    }
}

class Student {
	public String name;
	public int age;
	public int score;
    public Student(String name, int age,int score) {
        this.name = name;
        this.age=age;
        this.score = score;
    }
}*/

//通过上述代码可知：Map<K, V>是一种键-值映射表，当我们调用put(K key, V value)方法时，就把key和value做了映射并放入Map。当我们调用V get(K key)时，
//就可以通过key获取到对应的value。如果key不存在，则返回null。和List类似，Map也是一个接口，最常用的实现类是HashMap。
//
//如果只是想查询某个key是否存在，可以调用boolean containsKey(K key)方法。
//
//如果我们在存储Map映射关系的时候，对同一个key调用两次put()方法，分别放入不同的value，会有什么问题呢？例如：
/*
import java.util.HashMap;
import java.util.Map;
import  java.util.ArrayList;
public class 使用map {
    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap<>();
//        Map<String, Integer> x=new HashMap<>();
       Integer x=map.put("apple", 123);
       System.out.println("x="+x); //key="apple"已经存在，返回null     
        map.put("pear", 456);
        System.out.println(map.get("apple")); // 123
        Integer y=map.put("apple", 789); // 再次放入apple作为key，但value变为789
        System.out.println("y="+y); //key="apple"已经存在，返回被替换的value,因为put()方法的签名是V put(K key, V value)
        System.out.println(map.get("apple")); // 789

//        System.out.println(x);
        System.out.println(map.containsKey("apple"));
        System.out.println(map.containsKey("apple1"));
//        Object PRESENT = new Object();
//        System.out.println(PRESENT.toString());
    }
}*/

//重复放入key-value并不会有任何问题，但是一个key只能关联一个value。在上面的代码中，一开始我们把key对象"apple"映射到Integer对象123，然后再次
//调用put()方法把"apple"映射到789，这时，原来关联的value对象123就被“冲掉”了。实际上，put()方法的签名是V put(K key, V value)，如果放入
//的key已经存在，put()方法会返回被删除的旧的value，否则，返回null。

// 始终牢记：Map中不存在重复的key，因为放入相同的key，只会把原有的key-value对应的value给替换掉。
//此外，在一个Map中，虽然key不能重复，但value是可以重复的：
//
//Map<String, Integer> map = new HashMap<>();
//map.put("apple", 123);
//map.put("pear", 123); // ok

//遍历Map
//对Map来说，要遍历key可以使用for each循环遍历Map实例的keySet()方法返回的Set集合，它包含不重复的key的集合：

/*import java.util.HashMap;
import java.util.Map;
public class 使用map {
    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap<>();
        map.put("apple", 123);
        map.put("pear", 456);
        map.put("banana", 789);
        for (String key : map.keySet()) {
            Integer value = map.get(key);
            System.out.println(key + " = " + value);
        }
    }
}*/

//同时遍历key和value可以使用for each循环遍历Map对象的entrySet()集合，它包含每一个key-value映射：

/*import java.util.HashMap;
import java.util.Map;
public class 使用map {
    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap<>();
        map.put("apple", 123);
        map.put("pear", 456);
        map.put("banana", 789);
        for (Map.Entry<String, Integer> entry : map.entrySet()) {
            String key = entry.getKey();
            Integer value = entry.getValue();
            System.out.println(key + " = " + value);
        }
    }
}*/

//Map和List不同的是，Map存储的是key-value的映射关系，并且，它不保证顺序。在遍历的时候，遍历的顺序既不一定是put()时放入的key的顺序，也
//不一定是key的排序顺序。使用Map时，任何依赖顺序的逻辑都是不可靠的。以HashMap为例，假设我们放入"A"，"B"，"C"这3个key，遍历的时候，每
//个key会保证被遍历一次且仅遍历一次，但顺序完全没有保证，甚至对于不同的JDK版本，相同的代码遍历的输出顺序都是不同的！
//
//遍历Map时，不可假设输出的key是有序的！

//练习
//请编写一个根据name查找score的程序，并利用Map充当缓存，以提高查找效率：


import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class 使用map {
	public void main(String[] args) {

//        List<Student> list = List.of(
//            new Student("Bob", 78),
//            new Student("Alice", 85),
//            new Student("Brush", 66),
//            new Student("Newton", 99));
//    	var holder = new Students(list);
		System.out.println("测试失败!dsfsdafsdf");

		List<Student> list = new ArrayList<Student>();
		list.add(new Student("Bob", 78));
		list.add(new Student("Alice", 85));
		list.add(new Student("Brush", 66));
		list.add(new Student("Newton", 99));
		Students holder = new Students(list);

		System.out.println(holder.getScore("Bob") == 78 ? "测试成功!" : "测试失败!");
		System.out.println(holder.getScore("Alice") == 85 ? "测试成功!" : "测试失败!");
		System.out.println(holder.getScore("Tom") == -1 ? "测试成功!" : "测试失败!");
	}
}

class Students {
	List<Student> list;
	Map<String, Integer> cache;

	Students(List<Student> list) {
		this.list = list;
		this.cache = new HashMap<String, Integer>();
      //cache = new HashMap<>();
		//for(Student s:list) {
		//	cache.put(s.name, s.score);
		//}
	}

	
	//根据name查找score，找到返回score，未找到返回-1
	int getScore(String name) {
		// 先在Map中查找:
		Integer score = this.cache.get(name);
		System.out.println(name + ": " + score);
		if (score == null) {
			// TODO:
			score = findInList(name);
			if (score != null) {
				cache.put(name, score);

				// key的索引值
				int code = name.hashCode();
				System.out.println("code:" + code);
			}
		}
		return score == null ? -1 : score.intValue();
	}

	Integer findInList(String name) {
      //for (var ss : this.list) {
		for (Student ss : this.list) {
			if (ss.name.equals(name)) {
				return ss.score;
			}
		}
		return null;
	}
}

class Student {
	String name;
	int score;

	Student(String name, int score) {
		this.name = name;
		this.score = score;
	}
}
